package chatServer;

import java.net.*;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.io.*;

import messenger.CommCommand;
import messenger.Contact;
import messenger.Message;
import messenger.MessageLog;

/**
 * @author (Group 42) William Orem, Joseph Hamilton, Kevin Benik
 *
 */
public class ChatServerThread extends Thread {

	private Socket socket = null;
	private ObjectOutputStream out = null;
	private ObjectInputStream in = null;
	private UserDB user;
	private ConversDB db = null;
	private Contact tempuser;

	/**
	 * @param socket
	 * @param db
	 */
	public ChatServerThread(Socket socket, ConversDB db,boolean gui) {
		super("ChatServer");
		this.socket = socket;
		this.db = db;
	}

	/**
	 * @param newMessage
	 * @return
	 */
	public boolean addMEssage(Message newMessage) {
		UserDB toUser;
		if ((toUser = db.GetUser(newMessage.getTo())) != null) {
			// user message to exists..else drop it
			if (!db.getMessages().containsKey(toUser))
				db.getMessages().put(toUser, new ArrayList<Message>());
			db.getMessages().get(toUser).add(newMessage);
			System.err.println("saving message "
					+ db.getMessages().get(toUser).get(0).getBody());
			// save message in to user log
			if (!db.getMessagelog().containsKey(toUser)) {
				db.getMessagelog().put(toUser, new MessageLog());
				db.getMessagelog().get(toUser)
						.setStartDate(new GregorianCalendar());
			}
			db.getMessagelog().get(toUser).getMessages().add(newMessage);
			db.getMessagelog().get(toUser).setStopDate(new GregorianCalendar());
			// log in users log too
			if (!db.getMessagelog().containsKey(user)) {
				db.getMessagelog().put(user, new MessageLog());
				db.getMessagelog().get(user)
						.setStartDate(new GregorianCalendar());
			}
			db.getMessagelog().get(user).getMessages().add(newMessage);
			db.getMessagelog().get(user).setStopDate(new GregorianCalendar());

			System.err.println("logging message "
					+ db.getMessages().get(toUser).get(0).getBody());
			db.saveState();
			return true;
		}
		return false;

	}

	/**
	 * @return
	 */
	public CommCommand process() {
		CommCommand command = CommCommand.WAIT;
		if (user != null && db.getMessages().containsKey(user)
				&& db.GetMessageCount(user) > 0) {
			command = CommCommand.SEND;
		}
		return command;
	}

	/**
	 * @return
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public CommCommand processInput() throws ClassNotFoundException,
			IOException {
		ChatPacket inPacket = null;
		CommCommand inCommand = CommCommand.WAIT;
		// if(in.available()>0){
		inPacket = (ChatPacket) in.readObject();
		inCommand = inPacket.getCommand();
		// }
		CommCommand command = CommCommand.WAIT;

		switch (inCommand) {
		case ADDCCONTACT:
			//if user doesnt exist add
			if(db.GetUser(((Contact) inPacket.getMsg(1)).getUserName())==null){
			db.getUsers().add(
					new UserDB((String) inPacket.getMsg(0), (Contact) inPacket
							.getMsg(1)));
			command = inCommand;
			}
			break;

		case GETALL:
			command = inCommand;
			break;

		case GETCONTACT:
			if (db.GetUser((String) inPacket.getMsg(0)) !=null && (tempuser = db.GetUser((String) inPacket.getMsg(0))
					.getContact()) != null)
				command = inCommand;
			break;

		case LOGIN:
			if (db.MatchUser((String) inPacket.getMsg(0),
					(String) inPacket.getMsg(1))) {
				user = db.GetUser((String) inPacket.getMsg(0));
				command = inCommand;
			} else{
				command = CommCommand.QUIT;
				System.err.println("bad password for "
					+ (String) inPacket.getMsg(0));
			}
			break;

		case QUIT:
			command = CommCommand.QUIT;
			break;

		case RECV:
			break;

		case SEND:
			Message newMessage = (Message) inPacket.getMsg(0);
			addMEssage(newMessage);
			break;

		case STAT:
			break;

		default:
			break;

		}
		return command;
	}

	/**
	 * @param command
	 * @throws IOException
	 */
	public void processOutput(CommCommand command) throws IOException {
		ChatPacket outPacket = null;
		switch (command) {
		case ADDCCONTACT:
			outPacket = new ChatPacket(CommCommand.OK);
			outPacket.setMsg(0, "OK");
			System.err.println("Added contact, Sent OK");
			db.saveState();
			break;

		case GETALL:
			outPacket = new ChatPacket(CommCommand.GETALL);
			int i=0;
			for(UserDB u : db.getUsers())
			{
				outPacket.setMsg(i, u.getContact());
				++i;
			}
			System.err.println("sending all contacts ");
			break;

		case GETCONTACT:
			outPacket = new ChatPacket(CommCommand.GETCONTACT);
			outPacket.setMsg(0, tempuser);
			System.err.println("sending contact " + tempuser);
			break;

		case LOGIN:
			outPacket = new ChatPacket(CommCommand.OK);
			outPacket.setMsg(0, "OK");
			System.err.println("Logged in "+user.getUserName() +", Sent OK");
			break;

		case QUIT:
			break;

		case SEND:
			outPacket = new ChatPacket(CommCommand.SEND);
			int j = 0;
			for (Message m : db.getMessages().get(user)) {
				outPacket.setMsg(j, m);
				++j;
			}
			System.err.println("sending message "
					+ db.getMessages().get(user).get(0).getBody());
			db.getMessages().get(user).clear();

			break;

		case STAT:
			break;

		case HELO:
			outPacket = new ChatPacket(CommCommand.HELO);
			outPacket.setMsg(0, "Chatserver");
			System.err.println("Sent Hello");

		default:
			outPacket = new ChatPacket(CommCommand.OK);
			outPacket.setMsg(0, "OK");
			break;

		}
		if (outPacket != null) {
			out.writeObject(outPacket);
			out.flush();

		}

	}

	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	public void run() {

		try {
			out = new ObjectOutputStream(socket.getOutputStream());
			System.err.println("session started with "+socket.getInetAddress());
			in = new ObjectInputStream(socket.getInputStream());
			CommCommand command = CommCommand.WAIT;

			processOutput(CommCommand.HELO);

			while (command != CommCommand.QUIT) {
				command = processInput();
				if (command == CommCommand.WAIT)
					command = process();
				processOutput(command);
				// System.err.println(command);
			}
			out.close();
			in.close();
			socket.close();

		} catch (IOException | ClassNotFoundException e) {
			// e.printStackTrace();
			System.err.println("Closing");
		}
	}

}